package cn.iocoder.yudao.module.pay.service.wallet;

import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.pay.controller.admin.wallet.vo.transaction.PayWalletTransactionPageReqVO;
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.transaction.AppPayWalletTransactionPageReqVO;
import cn.iocoder.yudao.module.pay.convert.wallet.PayWalletTransactionConvert;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
import cn.iocoder.yudao.module.pay.service.wallet.bo.WalletTransactionCreateReqBO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlRunner;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 钱包流水 Service 实现类
 *
 * @author jason
 */
@Service
@Slf4j
@Validated
public class PayWalletTransactionServiceImpl implements PayWalletTransactionService {

    /**
     * 钱包流水的 no 前缀
     */
    private static final String WALLET_NO_PREFIX = "W";

    @Resource
    private PayWalletService payWalletService;
    @Resource
    private PayWalletTransactionMapper payWalletTransactionMapper;
    @Resource
    private PayNoRedisDAO noRedisDAO;

    @Override
    public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
                                                                       AppPayWalletTransactionPageReqVO pageVO) {
        PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType);
        return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO.getType(), pageVO);
    }

    @Override
    public PageResult<PayWalletTransactionDO> getWalletTransactionPage(PayWalletTransactionPageReqVO pageVO) {
        return payWalletTransactionMapper.selectPage(pageVO.getWalletId(), null, pageVO);
    }

    @Override
    public PayWalletTransactionDO createWalletTransaction(WalletTransactionCreateReqBO bo) {
        PayWalletTransactionDO transaction = PayWalletTransactionConvert.INSTANCE.convert(bo)
                .setNo(noRedisDAO.generate(WALLET_NO_PREFIX));
        payWalletTransactionMapper.insert(transaction);
        return transaction;
    }

    @Override
    public PayWalletTransactionDO getWalletTransactionByNo(String no) {
        return payWalletTransactionMapper.selectByNo(no);
    }

    @Override
    public PayWalletTransactionDO getWalletTransaction(String bizId, PayWalletBizTypeEnum type) {
        return payWalletTransactionMapper.selectByBiz(bizId, type.getType());
    }

    @Override
    public Map<String, Object> betSum(String code, Integer bizType, int level) {
        Map<String, Object> res = new HashMap<>();
        if (level == 0) {
            return payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(sum(price), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where code = '" + code + "')"))
                    .get(0);
        }
        if (level == 1) {
            return  payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(sum(price), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where referrer = '" + code + "')"))
                    .get(0);
        }
        if (level == 2) {
            return payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(sum(price), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where referrer in (select code from member_user where referrer = '" + code + "'))"))
                    .get(0);
        }

        return res;
    }

    @Override
    public Map<String, Object> rechargeSum(String code, Integer bizType, int level) {
        Map<String, Object> res = new HashMap<>();
        if (level == 0) {
            return payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(count( distinct wallet_id), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where code = '" + code + "')"))
                    .get(0);
        }
        if (level == 1) {
            return  payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(count( distinct wallet_id), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where referrer = '" + code + "')"))
                    .get(0);
        }
        if (level == 2) {
            return payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
                            .select("IFNULL(count( distinct wallet_id), 0) as sum_p")
                            .lambda()
                            .eq(PayWalletTransactionDO::getBizType, String.valueOf(bizType))
                            .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where referrer in (select code from member_user where referrer = '" + code + "'))"))
                    .get(0);
        }

        return res;
    }

    @Override
    public List<PayWalletTransactionDO> list(String code, Integer bizType) {
        return payWalletTransactionMapper.selectList(new LambdaQueryWrapper<PayWalletTransactionDO>()
                .orderByAsc(PayWalletTransactionDO::getCreateTime)
                .eq(PayWalletTransactionDO::getBizType, bizType)
                .inSql(PayWalletTransactionDO::getWalletId, "select id from pay_wallet where user_id  in (select id from member_user where code = '" + code + "')"));
    }


    @Override
    public List<Map<String, Object>> list2(String code, Integer bizType, LocalDate startTime, LocalDate endTime) {

        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        String l_1_sql = getL_1_sql(code);

        String l_2_sql = getL_2_sql(code);

        String sql = "select DATE_FORMAT(A1.Fdate,'%d/%m/%Y') as Fdate,IFNULL(a1.sun_f * -1,0) as sun_f,IFNULL(a1.sun_f * -1,0) as sun_s from "+
                        "(select Date(create_time) as Fdate,IFNULL( sum( price ), 0 ) as sun_f " +
                        " FROM pay_wallet_transaction  WHERE  deleted = 0 AND tenant_id = 1 " +
                        " and create_time > '" + startTime.format(fmt) + "'" +
                        " and create_time < '" + endTime.format(fmt) + "'" +
                        " and biz_type = " + bizType.toString() +
                        "  and wallet_id in (" + l_1_sql + ")"+
                        " GROUP BY Date(create_time) ) A1 LEFT JOIN" +
                        " (select Date(create_time) as Fdate,IFNULL( sum( price ), 0 ) as sun_s "+
                        " FROM pay_wallet_transaction WHERE deleted = 0 AND tenant_id = 1 "+
                        " and create_time > '" + startTime.format(fmt) + "'" +
                        " and create_time < '" + endTime.format(fmt) + "'" +
                        "   and biz_type = " + bizType.toString() +
                        "  and wallet_id in (" + l_2_sql + ")"+
                        " GROUP BY Date(create_time) ) A2 "+
                        " on(A1.Fdate = A2.Fdate) ORDER BY Fdate DESC" ;

        return  SqlRunner.db().selectList(sql) ;

//        return payWalletTransactionMapper.selectMaps(new QueryWrapper<PayWalletTransactionDO>()
//                .select(sql));

    }
    

    public Map<String, Object> listSum(String code, Integer bizType, LocalDate startTime, LocalDate endTime){
        Map<String, Object> result = new HashMap<>() ;



        // 一级成员
        String l_1_sql = getL_1_sql(code);

        //二级成员
        String l_2_sql = getL_2_sql(code);

        //三级成员
        String l_3_sql = getL_3_sql(code);

        List<Map<String, Object>> l_1_data  = getLevel_sum("1",PayWalletBizTypeEnum.BET.getType(),startTime, endTime, l_1_sql);
        List<Map<String, Object>> l_2_data  = getLevel_sum("2",PayWalletBizTypeEnum.BET.getType(),startTime, endTime, l_2_sql);
        List<Map<String, Object>> l_3_data  = getLevel_sum("3",PayWalletBizTypeEnum.BET.getType(),startTime, endTime, l_3_sql);

        List<Map<String, Object>> list_data = new ArrayList<>() ;

        list_data.addAll(l_1_data) ;
        list_data.addAll(l_2_data) ;
        list_data.addAll(l_3_data) ;

        int l_1_count = 0;
        BigDecimal l_1_sum = new BigDecimal("0");
        int l_2_count = 0;
        BigDecimal l_2_sum = new BigDecimal("0");
        int l_3_count = 0;
        BigDecimal l_3_sum = new BigDecimal("0");
        for (int i = 0; i < list_data.size(); i++) {
            Map<String,Object> item  = list_data.get(i) ;
            int level =  Integer.parseInt(item.get("level").toString()) ;
            BigDecimal d = ((BigDecimal) item.get("level_sum")) ;
            switch(level){
                case 1 :
                    l_1_count ++ ;
                    l_1_sum.add(d) ;
                    break; //可选
                case 2 :
                    l_2_count ++ ;
                    l_2_sum.add(d) ;
                    break; //可选
                case 3 :
                    l_3_count ++ ;
                    l_3_sum.add(d) ;
                    break; //可选
            }

        }
        result.put("l_1_count",l_1_count) ;
        result.put("l_1_sum",l_1_sum) ;
        result.put("l_2_count",l_2_count) ;
        result.put("l_2_sum",l_2_sum) ;
        result.put("l_3_count",l_3_count) ;
        result.put("l_3_sum",l_3_sum) ;

        return  result ;
    }

    @NotNull
    //
    private static List<Map<String, Object>> getLevel_sum(String level,Integer bizType,LocalDate startTime, LocalDate endTime, String level_sql) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String sql = "select " + level +
                " as level, wallet_id,IFNULL( sum( price ), 0 ) as level_sum from pay_wallet_transaction" +
                " where biz_type =  " + bizType.toString() +
                " and deleted = 0 AND tenant_id = 1" +
                " and create_time > '" + startTime.format(fmt) + "'" +
                " and create_time < '" + endTime.format(fmt) + "'" +
                "  and wallet_id in (" + level_sql + ")"+
                " GROUP BY wallet_id" ;


        return SqlRunner.db().selectList(sql);
    }

    @NotNull
    private static String getL_3_sql(String code) {
        String l_3_sql  = "select id from pay_wallet WHERE user_id in" +
                " (select id from member_user where referrer in " +
                " (select id from member_user where referrer in " +
                " (select code from member_user where  deleted = 0 AND tenant_id = 1 and referrer ='"+ code +"')))" ;
        return l_3_sql;
    }

    @NotNull
    private static String getL_2_sql(String code) {
        String l_2_sql  = "select id from pay_wallet WHERE user_id in" +
                " ( select id from member_user where referrer in " +
                "(select code from member_user where  deleted = 0 AND tenant_id = 1 and referrer ='"+ code +"'))" ;
        return l_2_sql;
    }

    @NotNull
    private static String getL_1_sql(String code) {
        String l_1_sql  = "select id from pay_wallet WHERE user_id in " +
                "( select id from member_user where  deleted = 0 AND tenant_id = 1 and referrer ='"+ code +"')" ;
        return l_1_sql;
    }

    public List<Map<String, Object>> referrerList(String code, LocalDate startTime, LocalDate endTime){
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");

        String cz_sql  = "select wallet_id,IFNULL( sum( price ), 0 ) as sun_f,count(id) as sun_count from pay_wallet_transaction " +
                "where deleted = 0 AND tenant_id = 1 and biz_type=1" +
                " and create_time > '" + startTime.format(fmt) + "'" +
                " and create_time < '" + endTime.format(fmt) + "'" +
                "  GROUP BY wallet_id" ;
        String tx_sql  = "select wallet_id,IFNULL( sum( price ), 0 ) as sun_f,count(id) as sun_count from pay_wallet_transaction " +
                "where deleted = 0 AND tenant_id = 1 and biz_type=11" +
                " and create_time > '" + startTime.format(fmt) + "'" +
                " and create_time < '" + endTime.format(fmt) + "'" +
                "  GROUP BY wallet_id" ;

        String sql  = "select id,user_id,balance," +
                "IFNULL(a1.sun_f,0) as sum_cz,IFNULL(a1.sun_count,0) as sum_cz_count," +
                "IFNULL(a2.sun_f,0) as sum_tx,IFNULL(a2.sun_count,0) as sum_tx_count" +
                " from pay_wallet" +
                " left join (" + cz_sql +
                ") as a1 on(pay_wallet.id=a1.wallet_id)"+
                " left join (" + tx_sql +
                ") as a2 on(pay_wallet.id=a1.wallet_id)"+
                " WHERE user_id in " +
                "( select id from member_user where  deleted = 0 AND tenant_id = 1 and referrer ='"+ code +"')" ;

        return  SqlRunner.db().selectList(sql) ;
    }

}
